package com.lpssfxy.service.impl;

import com.lpssfxy.bean.R;
import com.lpssfxy.entity.RateMoreProduct;
import com.lpssfxy.entity.RecentlyRateMoreProduct;
import com.lpssfxy.entity.UserRecProduct;
import com.lpssfxy.service.StaticAndRecProductService;
import com.lpssfxy.utils.Constant;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;

import java.util.ArrayList;
import java.util.List;

@Service
public class StaticAndRecProductServiceImpl implements StaticAndRecProductService {
    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 获取评分次数最多的商品
     *
     * @return
     */
    @Override
    public R getRateMoreProductList() {
        // Product与RateMoreProducts两张表联合查询
        // 下面代码等价于db.RateMoreProducts.aggregate([ { "$lookup": { "from": "Product", "localField": "productId", "foreignField": "productId", "as": "ProductAndRateMore" } }, { "$sort": { "total": -1 } } ]).pretty()
        LookupOperation lookupOperation = LookupOperation.newLookup()
                .from(Constant.MONGODB_PRODUCT_COLLECTION) // 关联从表名称
                .localField("productId") // 主表关联字段
                .foreignField("productId") // 从表关联字段
                .as("products"); // 查询结果名称

        Sort sort = Sort.by("total").descending();
        SortOperation operation = new SortOperation(sort);

        Aggregation aggregation = Aggregation.newAggregation(lookupOperation, operation);

        List<RateMoreProduct> mappedResults = mongoTemplate.aggregate(aggregation, Constant.MONGODB_RATE_MORE_PRODUCTS_COLLECTION, RateMoreProduct.class).getMappedResults();

        List<RateMoreProduct> resultList = new ArrayList<>();

        // 历史热门商品这里选择推荐12个商品，你们可以自行定义要显示多少
        if (mappedResults.size() >= Constant.RECOMMEND_MAX_SIZE) {
            for (int i = 0; i < Constant.RECOMMEND_MAX_SIZE; i++) {
                resultList.add(mappedResults.get(i));
            }
        } else {
            resultList = mappedResults;
        }
        return R.ok().data("data", resultList);
    }

    /**
     * 获取最近（月）评分次数最多的商品
     *
     * @return
     */
    @Override
    public R getRecentlyRateMoreProductList() {
        // Product与RateMoreRecentlyProducts两张表联合查询
        // 下面代码等价于查询语句：db.RateMoreRecentlyProducts.aggregate([ { "$lookup": { "from": "Product", "localField": "productId", "foreignField": "productId", "as": "Products" } }, { "$sort": {"monthOfYear": -1,"total": -1 } } ]).pretty()
        LookupOperation lookupOperation = LookupOperation.newLookup()
                .from(Constant.MONGODB_PRODUCT_COLLECTION) // 关联从表名称
                .localField("productId") // 主表关联字段
                .foreignField("productId") // 从表关联字段
                .as("products"); // 查询结果名称

        Sort sort = Sort.by("monthOfYear", "total").descending();
        SortOperation operation = new SortOperation(sort);

        Aggregation aggregation = Aggregation.newAggregation(lookupOperation, operation);

        List<RecentlyRateMoreProduct> mappedResults = mongoTemplate.aggregate(aggregation, Constant.MONGODB_RATE_MORE_PRODUCTS_RECENTLY_COLLECTION, RecentlyRateMoreProduct.class).getMappedResults();

        List<RecentlyRateMoreProduct> resultList = new ArrayList<>();

        // 最近热门商品这里选择推荐12个商品，你们可以自行定义要显示多少
        if (mappedResults.size() >= Constant.RECOMMEND_MAX_SIZE) {
            for (int i = 0; i < Constant.RECOMMEND_MAX_SIZE; i++) {
                resultList.add(mappedResults.get(i));
            }
        } else {
            resultList = mappedResults;
        }
        return R.ok().data("data", resultList);
    }

    /**
     * 离线计算得到的用户商品推荐列表：
     * 根据用户id查询当前用户的离线推荐结果
     * 查询语句如下：
     * db.UserRecs.aggregate([
     * {'$match':{"userId":50130}},
     * {$unwind:"$recs"},
     * {$lookup:{from:"product",localField:"recs.productId",foreignField: "productId",as: "product"}},
     * {$unwind:"$product"},
     * {$group:{_id:{"userId":"$userId"},"products":{$push:"$product"},"count":{'$sum': 1}}},
     * {$project:{"userId":"$_id.userId","products":"$products","len": {$size: "$products"}}}
     * ]).pretty()
     */
    @Override
    public R getOfflineRecs(Integer userId) {
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("userId").is(userId)),
                Aggregation.unwind("recs"),
                Aggregation.lookup(Constant.MONGODB_PRODUCT_COLLECTION, "$recs.productId", "productId", "product"),
                Aggregation.unwind("$product"),
                Aggregation.group("userId").push("$product").as("productList"),
                Aggregation.project("userId", "productList")
        );

        List<UserRecProduct> mappedResults = mongoTemplate.aggregate(aggregation, Constant.MONGODB_USER_RECS_COLLECTION, UserRecProduct.class).getMappedResults();

        return R.ok().data("data", mappedResults);
    }

    /**
     * 实时计算得到的用户商品推荐列表：
     * 根据用户id查询当前用户的推荐结果
     * 查询语句如下：
     * db.StreamRecs.aggregate([
     * {$match:{"userId":50130}},
     * {$unwind:"$recs"},
     * {$lookup:{from:"product",localField:"recs.productId",foreignField: "productId",as: "product"}},
     * {$unwind:"$product"},
     * {$group:{_id:{"userId":"$userId"},"products":{$push:"$product"}}},
     * {$project:{"userId":"$_id.userId","products":"$products"}}
     * ]).pretty()
     */
    @Override
    public R getRealtimeRecs(Integer userId) {
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("userId").is(userId)),
                Aggregation.unwind("recs"),
                Aggregation.lookup(Constant.MONGODB_PRODUCT_COLLECTION, "$recs.productId", "productId", "product"),
                Aggregation.unwind("$product"),
                Aggregation.group("userId").push("$product").as("productList"),
                Aggregation.project("userId", "productList")
        );

        List<UserRecProduct> mappedResults = mongoTemplate.aggregate(aggregation, Constant.MONGODB_STREAM_RECS_COLLECTION, UserRecProduct.class).getMappedResults();

        return R.ok().data("data", mappedResults);
    }
}
